home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Source / GNU / cctools / as / m88k.c < prev    next >
C/C++ Source or Header  |  1993-09-09  |  33KB  |  1,667 lines

  1. /* m88k.c -- Assemble for the 88100
  2.    Copyright (C) 1989 Free Software Foundation, Inc.
  3.  
  4. This file is not yet part of GAS, the GNU Assembler.
  5.  
  6. GAS is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GAS is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GAS; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include <ctype.h>
  21. #include <string.h>
  22. #include <mach-o/m88k/reloc.h>
  23. #include "m88k-opcode.h"
  24. #include "as.h"
  25. #include "flonum.h"
  26. #include "expr.h"
  27. #include "hash.h"
  28. #include "frags.h"
  29. #include "fixes.h"
  30. #include "read.h"
  31. #include "md.h"
  32. #include "obstack.h"
  33. #include "symbols.h"
  34. #include "messages.h"
  35. #include "input-scrub.h"
  36. #include "sections.h"
  37.  
  38. /*
  39.  * These are the default cputype and cpusubtype for the m88k architecture.
  40.  */
  41. const cpu_type_t md_cputype = CPU_TYPE_MC88000;
  42. cpu_subtype_t md_cpusubtype = CPU_SUBTYPE_MC88000_ALL;
  43.  
  44. /* This is the byte sex for the m88k architecture */
  45. const enum byte_sex md_target_byte_sex = BIG_ENDIAN_BYTE_SEX;
  46.  
  47. #ifdef NeXT
  48. static long in_delay_slot = 0;
  49. #endif
  50.  
  51. static char *cmpslot[] = { "**", "**", "eq", "ne", "gt", "le", "lt", "ge",
  52.                "hi", "ls", "lo", "hs",
  53. #ifdef m88110
  54.                "be", "nb", "he", "nh",
  55. #endif m88110
  56.                 NULL };
  57.  
  58. static struct {
  59.     char *name;
  60.     unsigned int num;
  61.  
  62. } cndmsk[] = {
  63.         "eq0", 0x02,
  64.         "ne0", 0x0d,
  65.         "gt0", 0x01,
  66.         "lt0", 0x0c,
  67.         "ge0", 0x03,
  68.         "le0", 0x0e,
  69.         NULL,  0x00,
  70.           };
  71.  
  72. struct m88k_insn {
  73.         unsigned long opcode;
  74.         expressionS exp;
  75. #ifdef NeXT
  76.         enum reloc_type_m88k reloc;
  77. #else
  78.         enum reloc_type reloc;
  79. #endif
  80. };
  81.  
  82. static struct hash_control *op_hash = NULL;
  83.  
  84. /* These chars start a comment anywhere in a source file (except inside
  85.    another comment */
  86. const char md_comment_chars[] = ";";
  87.  
  88. /* These chars only start a comment at the beginning of a line. */
  89. const char md_line_comment_chars[] = "#";
  90.  
  91. /* Chars that can be used to separate mant from exp in floating point nums */
  92. const char md_EXP_CHARS[] = "eE";
  93.  
  94. /* Chars that mean this number is a floating point constant */
  95. /* as in 0f123.456 */
  96. /* or    0H1.234E-12 (see exp chars above) */
  97. const char md_FLT_CHARS[] = "dDfF";
  98.  
  99. static int calcop(
  100.     struct m88k_opcode *format,
  101.     char *param,
  102.     struct m88k_insn *insn);
  103. static char * parse_reg(
  104.     char *param,
  105.     struct m88k_insn *insn,
  106.     struct m88k_opcode *format,
  107.     int parcnt);
  108. #ifdef m88110
  109. static char *parse_ereg(
  110.     char *param,
  111.     struct m88k_insn *insn,
  112.     struct m88k_opcode *format,
  113.     int parcnt);
  114. static char *parse_e4rot(
  115.     char *param,
  116.     struct m88k_insn *insn,
  117.     struct m88k_opcode *format,
  118.     int parcnt);
  119. static char *parse_xreg(
  120.     char *param,
  121.     struct m88k_insn *insn,
  122.     struct m88k_opcode *format,
  123.     int parcnt);
  124. #endif m88110
  125. static char *parse_pcr(
  126.     char *param,
  127.     struct m88k_insn *insn,
  128.     struct m88k_opcode *format,
  129.     int parcnt);
  130. static char *parse_cmp(
  131.     char *param,
  132.     struct m88k_insn *insn,
  133.     struct m88k_opcode *format,
  134.     int parcnt);
  135. static char *parse_cnd(
  136.     char *param,
  137.     struct m88k_insn *insn,
  138.     struct m88k_opcode *format,
  139.     int parcnt);
  140. static char *parse_bf(
  141.     char *param,
  142.     struct m88k_insn *insn,
  143.     struct m88k_opcode *format,
  144.     int parcnt);
  145. static char *parse_rot(
  146.     char *param,
  147.     struct m88k_insn *insn,
  148.     struct m88k_opcode *format,
  149.     int parcnt);
  150. static char *parse_rsc(
  151.     char *param,
  152.     struct m88k_insn *insn,
  153.     struct m88k_opcode *format,
  154.     int parcnt);
  155. static char *parse_cr(
  156.     char *param,
  157.     struct m88k_insn *insn,
  158.     struct m88k_opcode *format,
  159.     int parcnt);
  160. static char *parse_fcr(
  161.     char *param,
  162.     struct m88k_insn *insn,
  163.     struct m88k_opcode *format,
  164.     int parcnt);
  165. static char *parse_cst(
  166.     char *param,
  167.     struct m88k_insn *insn,
  168.     struct m88k_opcode *format,
  169.     int parcnt);
  170. static char *getval(
  171.     char *param,
  172.     unsigned int *val);
  173. #ifdef NeXT
  174. static void s_reg(
  175.     int reg);
  176. static void s_scaled(
  177.     int value);
  178. static void s_m88k_abs(
  179.     int value);
  180. static void s_no_delay(
  181.     int value);
  182. static void s_dot(
  183.     int value);
  184. #endif /* NeXT */
  185.  
  186. const pseudo_typeS md_pseudo_table[] =
  187. {
  188. #ifdef NeXT
  189.     {"greg", s_reg, 'r' },
  190.     {"xreg", s_reg, 'x' },
  191.     {"scaled", s_scaled, 0},
  192.     {"abs", s_m88k_abs, 0},
  193.     {"no_delay", s_no_delay, 0},
  194.     {"dot", s_dot, 0},
  195. #endif
  196. #ifndef NeXT
  197.       /* At NeXT we don't allow these */
  198.     {"dfloat", float_cons, 'd'},
  199.     {"ffloat", float_cons, 'f'},
  200.     {"global", s_globl, 0},
  201.     {"half", cons, 2 },
  202.     {"ln", s_line, 0},
  203.     {"zero", s_space, 0},
  204.     {"word", cons, 4 },
  205. #endif
  206.     {0}
  207. };
  208.  
  209. #ifdef NeXT
  210. static
  211. void
  212. s_dot(
  213. int value)
  214. {
  215.     char *name, *end_name, delim;
  216.     symbolS *symbolP;
  217.  
  218.     if( * input_line_pointer == '"')
  219.       name = input_line_pointer + 1;
  220.     else
  221.       name = input_line_pointer;
  222.     delim = get_symbol_end();
  223.     end_name = input_line_pointer;
  224.     *end_name = 0;
  225.  
  226.     symbolP = symbol_find_or_make (name);
  227.     symbolP -> sy_type = N_ABS;
  228.     symbolP -> sy_other = 0; /* NO_SECT */
  229.     symbolP -> sy_value = obstack_next_free(&frags) - frag_now->fr_literal;
  230.     symbolP -> sy_frag = &zero_address_frag;
  231.  
  232.     *end_name = delim;
  233.     totally_ignore_line();
  234. }
  235. /*
  236.  * s_reg() is used to implement ".greg symbol,exp" and ".xreg symbol,exp"
  237.  * which set symbol to 1 or 0 depending on if the expression is a general
  238.  * register or extended register respectfully.  These are intended for use in
  239.  * macros.
  240.  */
  241. static
  242. void
  243. s_reg(
  244. int reg)
  245. {
  246.     char *name, *end_name, delim;
  247.     symbolS *symbolP;
  248.     unsigned long n_value, val;
  249.  
  250.     if( * input_line_pointer == '"')
  251.       name = input_line_pointer + 1;
  252.     else
  253.       name = input_line_pointer;
  254.     delim = get_symbol_end();
  255.     end_name = input_line_pointer;
  256.     *end_name = delim;
  257.     SKIP_WHITESPACE();
  258.     if ( * input_line_pointer != ',' ) {
  259.         *end_name = 0;
  260.         as_warn("Expected comma after name \"%s\"", name);
  261.         *end_name = delim;
  262.         ignore_rest_of_line();
  263.         return;
  264.     }
  265.     input_line_pointer ++;
  266.     *end_name = 0;
  267.  
  268.     SKIP_WHITESPACE();
  269.     n_value = 0;
  270.     if (*input_line_pointer == reg || *input_line_pointer == toupper(reg)){
  271.         input_line_pointer++;
  272.         if(isdigit(*input_line_pointer)){
  273.         val = 0;
  274.         while (isdigit(*input_line_pointer)){
  275.             if ((val = val * 10 + *input_line_pointer++ - '0') > 31)
  276.             break;
  277.         }
  278.         SKIP_WHITESPACE();
  279.         if(val <= 31 &&
  280.            (*input_line_pointer == '\n' || *input_line_pointer == '@'))
  281.             n_value = 1;
  282.         }
  283.     }
  284.  
  285.     symbolP = symbol_find_or_make (name);
  286.     symbolP -> sy_type = N_ABS;
  287.     symbolP -> sy_other = 0; /* NO_SECT */
  288.     symbolP -> sy_value = n_value;
  289.     symbolP -> sy_frag = &zero_address_frag;
  290.  
  291.     *end_name = delim;
  292.     totally_ignore_line();
  293. }
  294.  
  295. /*
  296.  * s_scaled() is used to implement ".scaled symbol,exp" which sets symbol to 1
  297.  * or 0 depending on if the expression is a scaled general register expression
  298.  * "r1[r2]" or not respectfully.  This is intended for use in macros.
  299.  */
  300. static
  301. void
  302. s_scaled(
  303. int value)
  304. {
  305.     char *name, *end_name, delim;
  306.     symbolS *symbolP;
  307.     unsigned long n_value, val;
  308.  
  309.     if( * input_line_pointer == '"')
  310.       name = input_line_pointer + 1;
  311.     else
  312.       name = input_line_pointer;
  313.     delim = get_symbol_end();
  314.     end_name = input_line_pointer;
  315.     *end_name = delim;
  316.     SKIP_WHITESPACE();
  317.     if ( * input_line_pointer != ',' ) {
  318.         *end_name = 0;
  319.         as_warn("Expected comma after name \"%s\"", name);
  320.         *end_name = delim;
  321.         ignore_rest_of_line();
  322.         return;
  323.     }
  324.     input_line_pointer ++;
  325.     *end_name = 0;
  326.  
  327.     SKIP_WHITESPACE();
  328.     n_value = 0;
  329.     if (*input_line_pointer == 'r' || *input_line_pointer == 'R'){
  330.         input_line_pointer++;
  331.         if(isdigit(*input_line_pointer)){
  332.         val = 0;
  333.         while (isdigit(*input_line_pointer)){
  334.             if ((val = val * 10 + *input_line_pointer++ - '0') > 31)
  335.             break;
  336.         }
  337.         SKIP_WHITESPACE();
  338.         if(val <= 31 && *input_line_pointer == '['){
  339.             input_line_pointer++;
  340.             if (*input_line_pointer == 'r' ||
  341.             *input_line_pointer == 'R'){
  342.             input_line_pointer++;
  343.             if(isdigit(*input_line_pointer)){
  344.                 val = 0;
  345.                 while (isdigit(*input_line_pointer)){
  346.                 if ((val = val * 10 +
  347.                        *input_line_pointer++ - '0') > 31)
  348.                     break;
  349.                 }
  350.                 if(val <= 31 && *input_line_pointer == ']'){
  351.                 input_line_pointer++;
  352.                 SKIP_WHITESPACE();
  353.                 if(*input_line_pointer == '\n' ||
  354.                    *input_line_pointer == '@')
  355.                         n_value = 1;
  356.                 }
  357.             }
  358.             }
  359.         }
  360.         }
  361.     }
  362.  
  363.     symbolP = symbol_find_or_make (name);
  364.     symbolP -> sy_type = N_ABS;
  365.     symbolP -> sy_other = 0; /* NO_SECT */
  366.     symbolP -> sy_value = n_value;
  367.     symbolP -> sy_frag = & zero_address_frag;
  368.  
  369.     *end_name = delim;
  370.     totally_ignore_line();
  371. }
  372.  
  373. /*
  374.  * s_m88k_abs() is used to implement ".abs symbol,exp" which sets symbol to 1
  375.  * or 0 depending on if the expression is an absolute expression or not
  376.  * respectfully.  This is intended for use in macros.
  377.  */
  378. static
  379. void
  380. s_m88k_abs(
  381. int value)
  382. {
  383.     char *name, *end_name, delim, *start;
  384.     symbolS *symbolP;
  385.     unsigned long n_value, val, is_reg_exp;
  386.  
  387.     start = input_line_pointer;
  388.     if( * input_line_pointer == '"')
  389.       name = input_line_pointer + 1;
  390.     else
  391.       name = input_line_pointer;
  392.     delim = get_symbol_end();
  393.     end_name = input_line_pointer;
  394.     *end_name = delim;
  395.     SKIP_WHITESPACE();
  396.     if ( * input_line_pointer != ',' ) {
  397.         *end_name = 0;
  398.         as_warn("Expected comma after name \"%s\"", name);
  399.         *end_name = delim;
  400.         ignore_rest_of_line();
  401.         return;
  402.     }
  403.     input_line_pointer ++;
  404.     *end_name = 0;
  405.  
  406.     SKIP_WHITESPACE();
  407.     is_reg_exp = 0;
  408.     n_value = 0;
  409.     if(*input_line_pointer == 'r' || *input_line_pointer == 'R'){
  410.         input_line_pointer++;
  411.         if(isdigit(*input_line_pointer)){
  412.         val = 0;
  413.         while (isdigit(*input_line_pointer)){
  414.             if ((val = val * 10 + *input_line_pointer++ - '0') > 31)
  415.             break;
  416.         }
  417.         SKIP_WHITESPACE();
  418.         if(val <= 31)
  419.             is_reg_exp = 1;
  420.         }
  421.     }
  422.     if(is_reg_exp == 0){
  423.         *end_name = delim;
  424.         input_line_pointer = start;
  425.         s_abs(value);
  426.         return;
  427.     }
  428.  
  429.     symbolP = symbol_find_or_make (name);
  430.     symbolP -> sy_type = N_ABS;
  431.     symbolP -> sy_other = 0; /* NO_SECT */
  432.     symbolP -> sy_value = n_value;
  433.     symbolP -> sy_frag = & zero_address_frag;
  434.     *end_name = delim;
  435.  
  436.     totally_ignore_line();
  437. }
  438.  
  439. /*
  440.  * s_no_delay() is used to implement ".no_delay string" which will abort and
  441.  * print the string if the last instruction assembled has a delay slot.
  442.  * This is intended for use in macros that expand to more than one instruction
  443.  * that could be put in delay slots.  This is not really correct in it's
  444.  * operation in that it is not per-section and does not take into account
  445.  * anything other than assembled instructions.
  446.  */
  447. static
  448. void
  449. s_no_delay(
  450. int value)
  451. {
  452.     char *p, c;
  453.  
  454.     p = input_line_pointer;
  455.     while(*p != '\n' && *p != '@' && *p != '\0')
  456.         p++;
  457.     c = *p;
  458.     *p = '\0';
  459.     
  460.     if(in_delay_slot)
  461.         as_fatal("delay slot abort %s detected.  Assembly stopping.",
  462.              input_line_pointer);
  463.     input_line_pointer = p;
  464.     *p = c;
  465. }
  466. #endif /* NeXT */
  467.  
  468. void
  469. md_begin(
  470. void)
  471. {
  472.     register char *retval = NULL;
  473.     register unsigned int i = 0;
  474.  
  475.     /* initialize hash table */
  476.  
  477.     op_hash = hash_new();
  478.     if (op_hash == NULL)
  479.         as_fatal("Could not initialize hash table");
  480.  
  481.     /* loop until you see the end of the list */
  482.  
  483.     while (*m88k_opcodes[i].name) {
  484.         char *name = m88k_opcodes[i].name;
  485.  
  486.         /* hash each mnemonic and record its position */
  487.  
  488.         retval = hash_insert(op_hash, name, (char *)&m88k_opcodes[i]);
  489.  
  490.         if (retval != NULL && *retval != '\0')
  491.             as_fatal("Can't hash instruction '%s':%s",
  492.                     m88k_opcodes[i].name, retval);
  493.  
  494.         /* skip to next unique mnemonic or end of list */
  495.  
  496.         for (i++; !strcmp(m88k_opcodes[i].name, name); i++);
  497.     }
  498. }
  499.  
  500. int
  501. md_parse_option(
  502. char **argP,
  503. int *cntP,
  504. char ***vecP)
  505. {
  506.     return (1);
  507. }
  508.  
  509. void
  510. md_assemble(
  511. char *op)
  512. {
  513.     char *param, *thisfrag;
  514.     struct m88k_opcode *format;
  515.     struct m88k_insn insn;
  516. #ifdef NeXT
  517.     long pcrel_reloc;
  518. #endif
  519.  
  520.     assert(op);
  521.  
  522.     /* skip over instruction to find parameters */
  523.  
  524.     /* *param != '\0' is need for instructions that have no parameters
  525.        like rte */
  526.     for (param = op; !isspace(*param) && *param != '\0' ; param++);
  527.     *param++ = '\0';
  528.  
  529.     /* try to find the instruction in the hash table */
  530.  
  531.     if ((format = (struct m88k_opcode *) hash_find(op_hash, op)) == NULL) {
  532.         as_warn("Invalid mnemonic '%s'", op);
  533.         return;
  534.     }
  535.  
  536.     /* try parsing this instruction into insn */
  537.  
  538.     while (!calcop(format,param,&insn))
  539.  
  540.         /* if it doesn't parse try the next instruction */
  541.  
  542.         if (!strcmp(format->name, format[1].name))
  543.             format++;
  544.         else {
  545.             as_warn("Parameter syntax error");
  546.             return;
  547.         }
  548.  
  549.     /* grow the current frag and plop in the opcode */
  550.  
  551.     thisfrag = frag_more(4);
  552.     md_number_to_chars(thisfrag, insn.opcode, 4);
  553. #ifdef NeXT
  554.     in_delay_slot = format->delay_slot;
  555. #endif
  556. #ifdef NeXT    /* generate stabs for debugging assembly code */
  557.     /*
  558.      * If the -g flag is present generate a line number stab for the
  559.      * instruction.
  560.      * 
  561.      * See the detailed comments about stabs in read_a_source_file() for a
  562.      * description of what is going on here.
  563.      */
  564.     if(flagseen['g'] && frchain_now->frch_nsect == text_nsect){
  565.         (void)symbol_new(
  566.           "",
  567.           68 /* N_SLINE */,
  568.           text_nsect,
  569.           logical_input_line /* n_desc, line number */,
  570.           obstack_next_free(&frags) - frag_now->fr_literal,
  571.           frag_now);
  572.     }
  573. #endif /* NeXT */
  574.  
  575. #ifdef NeXT
  576.     pcrel_reloc = 0;
  577.     if (insn.reloc == M88K_RELOC_PC16 || insn.reloc == M88K_RELOC_PC26){
  578.         /*
  579.          * The NeXT linker has the ability to scatter blocks of
  580.          * sections between labels.  This requires that brances to
  581.          * labels that survive to the link phase must be able to
  582.          * be relocated.
  583.          */
  584.         if(insn.exp.X_add_symbol != NULL &&
  585.            (insn.exp.X_add_symbol->sy_name[0] != 'L' || flagseen ['L']))
  586.         pcrel_reloc = 1;
  587.         else
  588.         pcrel_reloc = 0;
  589.     }
  590. #endif /* NeXT */
  591.  
  592.     /* if this instruction requires labels mark it for later */
  593.     switch (insn.reloc) {
  594.  
  595.         case NO_RELOC:
  596.                 break;
  597.  
  598.         case M88K_RELOC_LO16:
  599.         case M88K_RELOC_HI16:
  600.                 fix_new(
  601.                     frag_now,
  602. #ifdef NeXT
  603.                     thisfrag - frag_now->fr_literal,
  604.                     4,
  605. #else
  606.                     thisfrag - frag_now->fr_literal + 2,
  607.                     2,
  608. #endif
  609.                     insn.exp.X_add_symbol,
  610.                     insn.exp.X_subtract_symbol,
  611.                     insn.exp.X_add_number,
  612.                     0, 0,
  613.                     insn.reloc
  614.                 );
  615.                 break;
  616.  
  617. #ifndef NeXT
  618.         case M88K_RELOC_IW16:
  619.                 fix_new(
  620.                     frag_now,
  621.                     thisfrag - frag_now->fr_literal,
  622.                     4,
  623.                     insn.exp.X_add_symbol,
  624.                     insn.exp.X_subtract_symbol,
  625.                     insn.exp.X_add_number,
  626.                     0, 0,
  627.                     insn.reloc
  628.                 );
  629.                 break;
  630. #endif /* !defined(NeXT) */
  631.  
  632.         case M88K_RELOC_PC16:
  633.                 fix_new(
  634.                     frag_now,
  635. #ifdef NeXT
  636.                     thisfrag - frag_now->fr_literal,
  637.                     4,
  638. #else
  639.                     thisfrag - frag_now->fr_literal + 2,
  640.                     2,
  641. #endif
  642.                     insn.exp.X_add_symbol,
  643.                     insn.exp.X_subtract_symbol,
  644.                     insn.exp.X_add_number,
  645.                     1, pcrel_reloc,
  646.                     insn.reloc
  647.                 );
  648.                 break;
  649.  
  650.         case M88K_RELOC_PC26:
  651.                 fix_new(
  652.                     frag_now,
  653.                     thisfrag - frag_now->fr_literal,
  654.                     4,
  655.                     insn.exp.X_add_symbol,
  656.                     insn.exp.X_subtract_symbol,
  657.                     insn.exp.X_add_number,
  658.                     1, pcrel_reloc,
  659.                     insn.reloc
  660.                 );
  661.                 break;
  662.  
  663.         default:
  664.                 as_warn("Unknown relocation type");
  665.                 break;
  666.     }
  667. }
  668.  
  669. static
  670. int
  671. calcop(
  672. struct m88k_opcode *format,
  673. char *param,
  674. struct m88k_insn *insn)
  675. {
  676.     int parcnt;
  677.  
  678.     /* initial the passed structure */
  679.  
  680.     memset(insn, '\0', sizeof(*insn));
  681.     insn->reloc = NO_RELOC;
  682.     insn->opcode = format->opcode;
  683.  
  684.     /* parse all parameters */
  685.  
  686.     for (parcnt=0; parcnt<3 && format->op[parcnt].type != NIL; parcnt++) {
  687.  
  688.         switch (format->op[parcnt].type) {
  689.  
  690.             case CNST:
  691.                 param = parse_cst(param, insn, format, parcnt);
  692.                 break;
  693.  
  694.             case REG:
  695.                 param = parse_reg(param, insn, format, parcnt);
  696.                 break;
  697. #ifdef m88110
  698.             case EREG:
  699.                 param = parse_ereg(param, insn, format, parcnt);
  700.                 break;
  701.  
  702.             case E4ROT:
  703.                 param = parse_e4rot(param, insn, format,parcnt);
  704.                 break;
  705.  
  706.             case XREG:
  707.                 param = parse_xreg(param, insn, format, parcnt);
  708.                 break;
  709. #endif m88110
  710.             case BF:
  711.                 param = parse_bf(param, insn, format, parcnt);
  712.                 break;
  713.  
  714.             case ROT:
  715.                 param = parse_rot(param, insn, format, parcnt);
  716.                 break;
  717.  
  718.             case REGSC:
  719.                 param = parse_rsc(param, insn, format, parcnt);
  720.                 break;
  721.  
  722.             case CRREG:
  723.                 param = parse_cr(param, insn, format, parcnt);
  724.                 break;
  725.  
  726.             case FCRREG:
  727.                 param = parse_fcr(param, insn, format, parcnt);
  728.                 break;
  729.  
  730.             case PCREL:
  731.                 param = parse_pcr(param, insn, format, parcnt);
  732.                 break;
  733.  
  734.             case CONDMASK:
  735.                 param = parse_cnd(param, insn, format, parcnt);
  736.                 break;
  737.  
  738.             case CMPRSLT:
  739.                 param = parse_cmp(param, insn, format, parcnt);
  740.                 break;
  741.  
  742.             default:
  743.                 as_fatal("Unknown parameter type");
  744.         }
  745.  
  746.         /* see if parser failed or not */
  747.  
  748.         if (param == NULL)
  749.             return 0;
  750.     }
  751.  
  752.     return 1;
  753. }
  754.  
  755. static
  756. char *
  757. parse_pcr(
  758. char *param,
  759. struct m88k_insn *insn,
  760. struct m88k_opcode *format,
  761. int parcnt)
  762. {
  763.     char *saveptr, *saveparam;
  764.     segT seg;
  765.  
  766.     saveptr = input_line_pointer;
  767.     input_line_pointer = param;
  768.  
  769.     seg = expression(&insn->exp);
  770.  
  771.     saveparam = input_line_pointer;
  772.     input_line_pointer = saveptr;
  773.  
  774.     switch (format->op[parcnt].width) {
  775.  
  776.         case 16: insn->reloc = M88K_RELOC_PC16;
  777.              break;
  778.  
  779.         case 26: insn->reloc = M88K_RELOC_PC26;
  780.              break;
  781.  
  782.         default: as_warn("Strange PC relative width %d",
  783.                         format->op[parcnt].width);
  784.              break;
  785.     }
  786.  
  787.     return saveparam;
  788. }
  789.  
  790. static
  791. char *
  792. parse_reg(
  793. char *param,
  794. struct m88k_insn *insn,
  795. struct m88k_opcode *format,
  796. int parcnt)
  797. {
  798.     unsigned int val = 0;
  799.  
  800.     if (*param != 'r' && *param != 'R')
  801.         return NULL;
  802.  
  803.     param++;
  804.  
  805.     if (!isdigit(*param))
  806.         return NULL;
  807.  
  808.     while (isdigit(*param))
  809.         if ((val = val * 10 + *param++ - '0') > 31)
  810.             return NULL;
  811.  
  812.     insn->opcode |= val << format->op[parcnt].offset;
  813.  
  814.     switch (*param) {
  815.  
  816.         case '\0' :
  817.             if (parcnt == 2 || format->op[parcnt+1].type == NIL)
  818.                 return param;
  819.             else
  820.                 return NULL;
  821.  
  822.         case '['  :
  823.             if (parcnt != 2 && format->op[parcnt+1].type == REGSC)
  824.                 return param+1;
  825.             else
  826.                 return NULL;
  827.  
  828.         case ','  :
  829.             if (parcnt != 2 && format->op[parcnt+1].type != NIL)
  830.                 return param+1;
  831.             else
  832.                 return NULL;
  833.     }
  834.  
  835.     return NULL;
  836. }
  837.  
  838. #ifdef m88110
  839. static
  840. char *
  841. parse_ereg(
  842. char *param,
  843. struct m88k_insn *insn,
  844. struct m88k_opcode *format,
  845. int parcnt)
  846. {
  847.     unsigned int val = 0;
  848.  
  849.     if (*param != 'r' && *param != 'R')
  850.         return NULL;
  851.  
  852.     param++;
  853.  
  854.     if (!isdigit(*param))
  855.         return NULL;
  856.  
  857.     while (isdigit(*param))
  858.         if ((val = val * 10 + *param++ - '0') > 31)
  859.             return NULL;
  860.  
  861.     if((val & 0x1) != 0)
  862.         return NULL;
  863.  
  864.     insn->opcode |= val << format->op[parcnt].offset;
  865.  
  866.     switch (*param) {
  867.  
  868.         case '\0' :
  869.             if (parcnt == 2 || format->op[parcnt+1].type == NIL)
  870.                 return param;
  871.             else
  872.                 return NULL;
  873.  
  874.         case '['  :
  875.             if (parcnt != 2 && format->op[parcnt+1].type == REGSC)
  876.                 return param+1;
  877.             else
  878.                 return NULL;
  879.  
  880.         case ','  :
  881.             if (parcnt != 2 && format->op[parcnt+1].type != NIL)
  882.                 return param+1;
  883.             else
  884.                 return NULL;
  885.     }
  886.  
  887.     return NULL;
  888. }
  889.  
  890. static
  891. char *
  892. parse_e4rot(
  893. char *param,
  894. struct m88k_insn *insn,
  895. struct m88k_opcode *format,
  896. int parcnt)
  897. {
  898.     int val;
  899.     char *saveptr, save_c, *offset_ptr;
  900.         expressionS exp;
  901.     segT seg;
  902.  
  903.     /* Now step over the '<' and look for the offset expression before a
  904.        '>' and the end of line (which is a '\0' when we get here).  We
  905.        know there is a '\0' where the end of line was because that is
  906.        what parse_a_buffer() in read.c does before calling md_assemble */
  907.     if (*param++ != '<')
  908.         return NULL;
  909.     offset_ptr = param;
  910.     while(*param != '\0')
  911.         param++;
  912.     if(param == offset_ptr || param[-1] != '>')
  913.         return NULL;
  914.     param--;
  915.     save_c = *param;
  916.     *param = '\0';
  917.     saveptr = input_line_pointer;
  918.     input_line_pointer = offset_ptr;
  919.     seg = expression(&exp);
  920.     *param = save_c;
  921.     input_line_pointer = saveptr;
  922.     val = exp.X_add_number;
  923.     if(seg != SEG_ABSOLUTE || val > 60 || (val & 0x3) != 0)
  924.         return NULL;
  925.  
  926.     val >>= 2;
  927.     insn->opcode |= val << format->op[parcnt].offset;
  928.  
  929.     return param+1;
  930. }
  931.  
  932. static
  933. char *
  934. parse_xreg(
  935. char *param,
  936. struct m88k_insn *insn,
  937. struct m88k_opcode *format,
  938. int parcnt)
  939. {
  940.     unsigned int val = 0;
  941.  
  942.     if (*param != 'x' && *param != 'X')
  943.         return NULL;
  944.  
  945.     param++;
  946.  
  947.     if (!isdigit(*param))
  948.         return NULL;
  949.  
  950.     while (isdigit(*param))
  951.         if ((val = val * 10 + *param++ - '0') > 31)
  952.             return NULL;
  953.  
  954.     insn->opcode |= val << format->op[parcnt].offset;
  955.  
  956.     switch (*param) {
  957.  
  958.         case '\0' :
  959.             if (parcnt == 2 || format->op[parcnt+1].type == NIL)
  960.                 return param;
  961.             else
  962.                 return NULL;
  963.  
  964.         case '['  :
  965.             if (parcnt != 2 && format->op[parcnt+1].type == REGSC)
  966.                 return param+1;
  967.             else
  968.                 return NULL;
  969.  
  970.         case ','  :
  971.             if (parcnt != 2 && format->op[parcnt+1].type != NIL)
  972.                 return param+1;
  973.             else
  974.                 return NULL;
  975.     }
  976.  
  977.     return NULL;
  978. }
  979. #endif m88110
  980.  
  981. static
  982. char *
  983. parse_cmp(
  984. char *param,
  985. struct m88k_insn *insn,
  986. struct m88k_opcode *format,
  987. int parcnt)
  988. {
  989.     int val;
  990.     char *saveptr, save_c, *offset_ptr, c;
  991.         expressionS exp;
  992.     segT seg;
  993.  
  994.     /* look for the offset expression before a ',' */
  995.     c = *param;
  996.     if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' ||
  997.         c == '~'){
  998.         offset_ptr = param;
  999.         while(*param != ',')
  1000.             param++;
  1001.         if(param == offset_ptr || *param != ',')
  1002.             return NULL;
  1003.         save_c = *param;
  1004.         *param = '\0';
  1005.         saveptr = input_line_pointer;
  1006.         input_line_pointer = offset_ptr;
  1007.         seg = expression(&exp);
  1008.         *param = save_c;
  1009.         input_line_pointer = saveptr;
  1010.         val = exp.X_add_number;
  1011.         if(seg != SEG_ABSOLUTE ||
  1012.            val > (1 << format->op[parcnt].width) || val < 0)
  1013.             return NULL;
  1014.     } else {
  1015.         if (isupper(*param))
  1016.             *param = tolower(*param);
  1017.  
  1018.         if (isupper(*(param+1)))
  1019.             *(param+1) = tolower(*(param+1));
  1020.  
  1021.         for (val=0; cmpslot[val] != NULL; val++)
  1022.             if (!strncmp(param,cmpslot[val],2))
  1023.                 break;
  1024.  
  1025.         if (cmpslot[val] == NULL)
  1026.             return NULL;
  1027.  
  1028.         param += 2;
  1029.     }
  1030.  
  1031.     if (*param++ != ',')
  1032.         return NULL;
  1033.  
  1034.     insn->opcode |= val << format->op[parcnt].offset;
  1035.  
  1036.     return param;
  1037. }
  1038.  
  1039. static
  1040. char *
  1041. parse_cnd(
  1042. char *param,
  1043. struct m88k_insn *insn,
  1044. struct m88k_opcode *format,
  1045. int parcnt)
  1046. {
  1047.     int val;
  1048.     char *saveptr, save_c, *offset_ptr, c;
  1049.         expressionS exp;
  1050.     segT seg;
  1051.  
  1052.     /* look for the offset expression before a ',' */
  1053.     c = *param;
  1054.     if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' ||
  1055.         c == '~'){
  1056.         offset_ptr = param;
  1057.         while(*param != ',')
  1058.             param++;
  1059.         if(param == offset_ptr || *param != ',')
  1060.             return NULL;
  1061.         save_c = *param;
  1062.         *param = '\0';
  1063.         saveptr = input_line_pointer;
  1064.         input_line_pointer = offset_ptr;
  1065.         seg = expression(&exp);
  1066.         *param = save_c;
  1067.         input_line_pointer = saveptr;
  1068.         val = exp.X_add_number;
  1069.         if(seg != SEG_ABSOLUTE ||
  1070.            val > (1 << format->op[parcnt].width) || val < 0)
  1071.             return NULL;
  1072.     } else {
  1073.         if (isupper(*param))
  1074.             *param = tolower(*param);
  1075.  
  1076.         if (isupper(*(param+1)))
  1077.             *(param+1) = tolower(*(param+1));
  1078.  
  1079.         for (val=0; cndmsk[val].name != NULL; val++)
  1080.             if (!strncmp(param,cndmsk[val].name,3))
  1081.                 break;
  1082.  
  1083.         if (cndmsk[val].name == NULL)
  1084.             return NULL;
  1085.  
  1086.         val = cndmsk[val].num;
  1087.  
  1088.         param += 3;
  1089.     }
  1090.  
  1091.     if (*param++ != ',')
  1092.         return NULL;
  1093.  
  1094.     insn->opcode |= val << format->op[parcnt].offset;
  1095.  
  1096.     return param;
  1097. }
  1098.  
  1099. static
  1100. char *
  1101. parse_bf(
  1102. char *param,
  1103. struct m88k_insn *insn,
  1104. struct m88k_opcode *format,
  1105. int parcnt)
  1106. {
  1107.     int val, width;
  1108.     char *saveptr, save_c, *offset_ptr, c;
  1109.         expressionS exp;
  1110.     segT seg;
  1111.  
  1112.     /* We know there is a '\0' where the end of line was because that is
  1113.        what parse_a_buffer() in read.c does before calling md_assemble */
  1114.  
  1115.     /* First look for the width expression before a '<' */
  1116.     saveptr = input_line_pointer;
  1117.     input_line_pointer = param;
  1118.     while(*param != '<' && *param != '\0')
  1119.         param++;
  1120.     if(*param == '\0'){
  1121.         input_line_pointer = saveptr;
  1122.         return NULL;
  1123.     }
  1124.     save_c = *param;
  1125.     *param = '\0';
  1126.     seg = expression(&exp);
  1127.     *param = save_c;
  1128.     input_line_pointer = saveptr;
  1129.     width = exp.X_add_number;
  1130.     if(seg != SEG_ABSOLUTE || width > 32 || width < 0)
  1131.         return NULL;
  1132.  
  1133.     /* Now step over the '<' and look for the offset expression before a
  1134.        '>' and the end of line (which is a '\0' when we get here) */
  1135.     param++;
  1136.     c = *param;
  1137.     if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' ||
  1138.         c == '~'){
  1139.         offset_ptr = param;
  1140.         while(*param != '\0')
  1141.             param++;
  1142.         if(param != offset_ptr && param[-1] != '>')
  1143.             return NULL;
  1144.         param--;
  1145.         save_c = *param;
  1146.         *param = '\0';
  1147.         saveptr = input_line_pointer;
  1148.         input_line_pointer = offset_ptr;
  1149.         seg = expression(&exp);
  1150.         *param = save_c;
  1151.         input_line_pointer = saveptr;
  1152.         val = exp.X_add_number;
  1153.         if(seg != SEG_ABSOLUTE || val > 32 || val < 0)
  1154.             return NULL;
  1155.     }
  1156.     else {
  1157.         if (isupper(*param))
  1158.             *param = tolower(*param);
  1159.  
  1160.         if (isupper(*(param+1)))
  1161.             *(param+1) = tolower(*(param+1));
  1162.  
  1163.         for (val=0; cmpslot[val] != NULL; val++)
  1164.             if (!strncmp(param,cmpslot[val],2))
  1165.                 break;
  1166.  
  1167.         if (cmpslot[val] == NULL)
  1168.             return NULL;
  1169.  
  1170.         param += 2;
  1171.     }
  1172.     if (*param != '>')
  1173.         return NULL;
  1174.     insn->opcode |= width << 5;
  1175.     insn->opcode |= val;
  1176.  
  1177.     return param+1;
  1178. }
  1179.  
  1180. static
  1181. char *
  1182. parse_rot(
  1183. char *param,
  1184. struct m88k_insn *insn,
  1185. struct m88k_opcode *format,
  1186. int parcnt)
  1187. {
  1188.     int val;
  1189.     char *saveptr, save_c, *offset_ptr;
  1190.         expressionS exp;
  1191.     segT seg;
  1192.  
  1193.     /* Now step over the '<' and look for the offset expression before a
  1194.        '>' and the end of line (which is a '\0' when we get here).  We
  1195.        know there is a '\0' where the end of line was because that is
  1196.        what parse_a_buffer() in read.c does before calling md_assemble */
  1197.     if (*param++ != '<')
  1198.         return NULL;
  1199.     offset_ptr = param;
  1200.     while(*param != '\0')
  1201.         param++;
  1202.     if(param != offset_ptr && param[-1] != '>')
  1203.         return NULL;
  1204.     param--;
  1205.     save_c = *param;
  1206.     *param = '\0';
  1207.     saveptr = input_line_pointer;
  1208.     input_line_pointer = offset_ptr;
  1209.     seg = expression(&exp);
  1210.     *param = save_c;
  1211.     input_line_pointer = saveptr;
  1212.     val = exp.X_add_number;
  1213.     if(seg != SEG_ABSOLUTE && (val > 32 || val < 0))
  1214.         return NULL;
  1215.  
  1216.     insn->opcode |= val;
  1217.  
  1218.     return param+1;
  1219. }
  1220.  
  1221. static
  1222. char *
  1223. parse_rsc(
  1224. char *param,
  1225. struct m88k_insn *insn,
  1226. struct m88k_opcode *format,
  1227. int parcnt)
  1228. {
  1229.     unsigned int val = 0;
  1230.  
  1231.     if (*param != 'r' && *param != 'R')
  1232.         return NULL;
  1233.  
  1234.     param++;
  1235.  
  1236.     if (!isdigit(*param))
  1237.         return NULL;
  1238.  
  1239.     while (isdigit(*param))
  1240.         if ((val = val * 10 + *param++ - '0') > 31)
  1241.             return NULL;
  1242.  
  1243.     insn->opcode |= val << format->op[parcnt].offset;
  1244.  
  1245.     if (*param != ']' || *(param+1) != '\0')
  1246.         return NULL;
  1247.  
  1248.     return param+1;
  1249. }
  1250.  
  1251. static
  1252. char *
  1253. parse_cr(
  1254. char *param,
  1255. struct m88k_insn *insn,
  1256. struct m88k_opcode *format,
  1257. int parcnt)
  1258. {
  1259.     unsigned int val = 0;
  1260.  
  1261.     if (strncmp(param, "cr", 2))
  1262.         return NULL;
  1263.  
  1264.     param += 2;
  1265.  
  1266.     if (!isdigit(*param))
  1267.         return NULL;
  1268.  
  1269.     while (isdigit(*param))
  1270.         if ((val = val * 10 + *param++ - '0') > 63)
  1271.             return NULL;
  1272.  
  1273.     /*
  1274.      * the following fix is not as generic as I'd like, but the
  1275.      * hardware is real picky about this.    - bowen@cs.buffalo.edu
  1276.      * This fix is to make sure the S1 and S2 fields are the same.
  1277.      */
  1278.     insn->opcode |= (insn->opcode & 0x001f0000) >> 16;
  1279.  
  1280.     insn->opcode |= val << format->op[parcnt].offset;
  1281.  
  1282.     if (*param != '\0')
  1283.         return NULL;
  1284.  
  1285.     return param;
  1286. }
  1287.  
  1288. static
  1289. char *
  1290. parse_fcr(
  1291. char *param,
  1292. struct m88k_insn *insn,
  1293. struct m88k_opcode *format,
  1294. int parcnt)
  1295. {
  1296.     unsigned int val = 0;
  1297.  
  1298.     if (strncmp(param, "fcr", 3))
  1299.         return NULL;
  1300.  
  1301.     param += 3;
  1302.  
  1303.     if (!isdigit(*param))
  1304.         return NULL;
  1305.  
  1306.     while (isdigit(*param))
  1307.         if ((val = val * 10 + *param++ - '0') > 63)
  1308.             return NULL;
  1309.  
  1310.     /*
  1311.      * This is to make sure the S1 and S2 fields are the same.
  1312.      */
  1313.     insn->opcode |= (insn->opcode & 0x001f0000) >> 16;
  1314.  
  1315.     insn->opcode |= val << format->op[parcnt].offset;
  1316.  
  1317.     if (*param != '\0')
  1318.         return NULL;
  1319.  
  1320.     return param;
  1321. }
  1322.  
  1323. static
  1324. char *
  1325. parse_cst(
  1326. char *param,
  1327. struct m88k_insn *insn,
  1328. struct m88k_opcode *format,
  1329. int parcnt)
  1330. {
  1331.     char c, *saveptr, *saveparam;
  1332.     unsigned int val, nohilo = 0;
  1333.     segT seg;
  1334.         expressionS exp;
  1335.  
  1336.     c = *param;
  1337.     if (isdigit(c) || c == '(' || c == '-' || c == '+' || c == '!' ||
  1338.         c == '~'){
  1339.         saveptr = input_line_pointer;
  1340.         input_line_pointer = param;
  1341.         while(*param != '\0')
  1342.             param++;
  1343.         seg = expression(&exp);
  1344.         input_line_pointer = saveptr;
  1345.         val = exp.X_add_number;
  1346.         if(seg != SEG_ABSOLUTE || val > (1 << format->op[parcnt].width))
  1347.             return NULL;
  1348.     }
  1349.     else if (!strncmp(param,"hi16(",5))
  1350.  
  1351.         if (isdigit(*(param+5))) {
  1352.             param = getval(param+5,&val);
  1353.             val = (val & 0xffff0000) >> 16;
  1354.             if (*param++ != ')')
  1355.                 return NULL;
  1356.  
  1357.         } else
  1358.             insn->reloc = M88K_RELOC_HI16;
  1359.     else if (!strncmp(param,"lo16(",5))
  1360.  
  1361.         if (isdigit(*(param+5))) {
  1362.             param = getval(param+5,&val);
  1363.             val &= 0x0000ffff;
  1364.             if (*param++ != ')')
  1365.                 return NULL;
  1366.  
  1367.         } else
  1368.             insn->reloc = M88K_RELOC_LO16;
  1369.  
  1370. #ifndef NeXT
  1371.     else if (!strncmp(param,"iw16(",5))
  1372.  
  1373.         if (isdigit(*(param+5))) {
  1374.             param = getval(param+5,&val);
  1375.             val &= 0x0000ffff;
  1376.             if (*param++ != ')')
  1377.                 return NULL;
  1378.  
  1379.         } else
  1380.             insn->reloc = M88K_RELOC_IW16;
  1381. #endif /* !defined(NeXT) */
  1382.  
  1383.     else if (*param == 'r' && isdigit(*(param+1)))
  1384.  
  1385.         return NULL;
  1386.  
  1387.     else {
  1388.         insn->reloc = M88K_RELOC_LO16;
  1389.         nohilo = 1;
  1390.     }
  1391.  
  1392.     if (insn->reloc != NO_RELOC) {
  1393.  
  1394.         saveptr = input_line_pointer;
  1395.         input_line_pointer = param + (nohilo ? 0 : 5);
  1396.  
  1397.         seg = expression(&insn->exp);
  1398.  
  1399.         saveparam = input_line_pointer;
  1400.         input_line_pointer = saveptr;
  1401.  
  1402.         if (nohilo) {
  1403.  
  1404.             if (*saveparam != '\0')
  1405.                 return NULL;
  1406.  
  1407.             return saveparam;
  1408.         }
  1409.  
  1410.         if (*saveparam != ')')
  1411.             return NULL;
  1412.  
  1413.         return saveparam+1;
  1414.     }
  1415.  
  1416.     if ((1 << format->op[parcnt].width) <= val)
  1417.         return NULL;
  1418.  
  1419.     insn->opcode |= val << format->op[parcnt].offset;
  1420.  
  1421.     if (*param != '\0')
  1422.         return NULL;
  1423.  
  1424.     return param;
  1425. }
  1426.  
  1427. #define isoct(z) (z >= '0' && z <= '7')
  1428. #define ishex(z) ((z >= '0' && z <= '9') || (z >= 'a' && z <= 'f') || (z >= 'A' && z <= 'F'))
  1429. #define hexval(z) \
  1430.   (isdigit(z) ? (z) - '0' :        \
  1431.    islower(z) ? (z) - 'a' + 10 :    \
  1432.    (z) - 'A' + 10)
  1433.  
  1434. static
  1435. char *
  1436. getval(
  1437. char *param,
  1438. unsigned int *val)
  1439. {
  1440.     *val = 0;
  1441.  
  1442.     if (*param == '0' && (*(param+1) == 'x' || *(param+1) == 'X'))
  1443.  
  1444.         for (param += 2; ishex(*param); param++)
  1445.  
  1446.             if (*val > 0x0fffffff)
  1447.                 return param;
  1448.             else
  1449.                 *val = *val * 16 + hexval(*param);
  1450.  
  1451.     else if (*param == '0')
  1452.  
  1453.         for (param++; isoct(*param); param++)
  1454.  
  1455.             if (*val > 0x1fffffff)
  1456.                 return param;
  1457.             else
  1458.                 *val = *val * 8 + *param - '0';
  1459.  
  1460.     else
  1461.  
  1462.         for (; isdigit(*param); param++)
  1463.  
  1464.             *val = *val * 10 + *param - '0';
  1465.  
  1466.     return param;
  1467. }
  1468.  
  1469. void
  1470. md_number_to_chars(
  1471. char *buf,
  1472. long val,
  1473. int nbytes)
  1474. {
  1475.     switch(nbytes) {
  1476.  
  1477.         case 4:
  1478.             *buf++ = val >> 24;
  1479.             *buf++ = val >> 16;
  1480.         case 2:
  1481.             *buf++ = val >> 8;
  1482.         case 1:
  1483.             *buf = val;
  1484.             break;
  1485.  
  1486.         default:
  1487.             abort();
  1488.     }
  1489. }
  1490.  
  1491. void
  1492. md_number_to_imm(
  1493. unsigned char *buf,
  1494. long val,
  1495. int nbytes,
  1496. fixS *fixP,
  1497. int nsect)
  1498. {
  1499.     if(fixP->fx_r_type == NO_RELOC ||
  1500.        fixP->fx_r_type == M88K_RELOC_VANILLA) {
  1501.         switch (nbytes) {
  1502.             case 4:
  1503.                 *buf++ = val >> 24;
  1504.                 *buf++ = val >> 16;
  1505.             case 2:
  1506.                 *buf++ = val >> 8;
  1507.             case 1:
  1508.                 *buf = val;
  1509.                 break;
  1510.  
  1511.             default:
  1512.                 abort();
  1513.         }
  1514.         return;
  1515.     }
  1516.  
  1517.     switch (fixP->fx_r_type) {
  1518. #ifdef NeXT
  1519.             case M88K_RELOC_LO16:
  1520.                 buf[2] = val >> 8;
  1521.                 buf[3] = val;
  1522.                 break;
  1523.             case M88K_RELOC_HI16:
  1524.                 buf[2] = val >> 24;
  1525.                 buf[3] = val >> 16;
  1526.                 break;
  1527.  
  1528.             case M88K_RELOC_PC16:
  1529.                 val += 4;
  1530.                 buf[2] = val >> 10;
  1531.                 buf[3] = val >> 2;
  1532.                 break;
  1533.  
  1534.             case M88K_RELOC_PC26:
  1535.                 val += 4;
  1536.                 buf[0] |= (val >> 26) & 0x03;
  1537.                 buf[1] = val >> 18;
  1538.                 buf[2] = val >> 10;
  1539.                 buf[3] = val >> 2;
  1540.                 break;
  1541. #else /* !defined NeXT */
  1542.             case M88K_RELOC_LO16:
  1543.                 buf[0] = val >> 8;
  1544.                 buf[1] = val;
  1545.                 break;
  1546.  
  1547.             case M88K_RELOC_IW16:
  1548.                 buf[2] = val >> 8;
  1549.                 buf[3] = val;
  1550.                 break;
  1551.  
  1552.             case M88K_RELOC_HI16:
  1553.                 buf[0] = val >> 24;
  1554.                 buf[1] = val >> 16;
  1555.                 break;
  1556.  
  1557.             case M88K_RELOC_PC16:
  1558.                 val += 4;
  1559.                 buf[0] = val >> 10;
  1560.                 buf[1] = val >> 2;
  1561.                 break;
  1562.  
  1563.             case M88K_RELOC_PC26:
  1564.                 val += 4;
  1565.                 buf[0] |= (val >> 26) & 0x03;
  1566.                 buf[1] = val >> 18;
  1567.                 buf[2] = val >> 10;
  1568.                 buf[3] = val >> 2;
  1569.                 break;
  1570.  
  1571.             case M88K_RELOC_32:
  1572.                 buf[0] = val >> 24;
  1573.                 buf[1] = val >> 16;
  1574.                 buf[2] = val >> 8;
  1575.                 buf[3] = val;
  1576.                 break;
  1577. #endif /* !defined(NeXT) */
  1578.  
  1579.             default:
  1580.                 as_warn("Bad relocation type");
  1581.                 break;
  1582.     }
  1583. }
  1584.  
  1585. #define MAX_LITTLENUMS 6
  1586.  
  1587. /* Turn a string in input_line_pointer into a floating point constant of type
  1588.    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
  1589.    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
  1590.  */
  1591. char *
  1592. md_atof(
  1593. int type,
  1594. char *litP,
  1595. int *sizeP)
  1596. {
  1597.     int    prec;
  1598.     LITTLENUM_TYPE words[MAX_LITTLENUMS];
  1599.     LITTLENUM_TYPE *wordP;
  1600.     char    *t;
  1601.     char    *atof_ieee();
  1602.  
  1603.     switch(type) {
  1604.     case 'f':
  1605.     case 'F':
  1606.     case 's':
  1607.     case 'S':
  1608.         prec = 2;
  1609.         break;
  1610.  
  1611.     case 'd':
  1612.     case 'D':
  1613.     case 'r':
  1614.     case 'R':
  1615.         prec = 4;
  1616.         break;
  1617.  
  1618.     case 'x':
  1619.     case 'X':
  1620.         prec = 6;
  1621.         break;
  1622.  
  1623.     case 'p':
  1624.     case 'P':
  1625.         prec = 6;
  1626.         break;
  1627.  
  1628.     default:
  1629.         *sizeP=0;
  1630.         return "Bad call to MD_ATOF()";
  1631.     }
  1632.     t=atof_ieee(input_line_pointer,type,words);
  1633.     if(t)
  1634.         input_line_pointer=t;
  1635.  
  1636.     *sizeP=prec * sizeof(LITTLENUM_TYPE);
  1637.     for(wordP=words;prec--;) {
  1638.         md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
  1639.         litP+=sizeof(LITTLENUM_TYPE);
  1640.     }
  1641.     return "";    /* Someone should teach Dean about null pointers */
  1642. }
  1643.  
  1644. const relax_typeS md_relax_table[] = {0};
  1645.  
  1646. int
  1647. md_estimate_size_before_relax(
  1648. fragS *fragP,
  1649. int segment_type)
  1650. {
  1651.     as_fatal("internal error: Relaxation should never occur");
  1652.     return(0);
  1653. }
  1654.  
  1655. void
  1656. md_convert_frag(
  1657. fragS *fragP)
  1658. {
  1659.     as_fatal("internal error: Relaxation should never occur");
  1660. }
  1661.  
  1662. void
  1663. md_end(
  1664. void)
  1665. {
  1666. }
  1667.